package com.ayf.payment.game.api.task.partition;

import com.ayf.payment.game.api.dto.criteria.PartitionSelectCriteria;
import com.ayf.payment.game.api.entity.Partition;
import com.ayf.payment.game.api.service.PartitionService;
import com.ayf.payment.game.api.utils.DateTimeUtil;
import com.ayf.payment.game.api.utils.SnowFlakeUtils;
import com.swwx.charm.commons.lang.utils.LogPortal;
import com.swwx.charm.zookeeper.exception.GetLockFailedException;
import com.swwx.charm.zookeeper.exception.ReleaseLockFailedException;
import com.swwx.charm.zookeeper.lock.DistributedLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @author wwl
 * @description:
 * @date 2020/12/24 17:26
 */
@Component
public abstract class PartitionChangeNameQueryTask {

    @Autowired
    private PartitionService partitionService;

    protected void run(DistributedLock distributedLock) {
        boolean lock = false;
        String lockName = this.getClass().getSimpleName().concat(System.getenv("XY_GAME_PAY_LOCK_FLAG"));
        String traceId = SnowFlakeUtils.getTraceId();
        try {
            if (lock = distributedLock.getLock(lockName)) {
                LogPortal.info("{} >>> get lock and run {} ", traceId, lockName);
                //更新分区名称
                String autoeissueTime = DateTimeUtil.getTimeMinutes(DateTimeUtil.addMinute(new Date(),1));
                PartitionSelectCriteria criteria = new PartitionSelectCriteria();
                criteria.setStartTime(autoeissueTime);
                final List<Partition> list = partitionService.selectByChangeNameTime(criteria);
                LogPortal.info("{} >>> {} 开始处理定时开区任务，共 {} 条记录", traceId, lockName, list.size());
                if (list.size() <= 0) {
                    return;
                }
                //初始化信号
                final CountDownLatch countDownLatch = new CountDownLatch(list.size());
                for (final Partition dto : list) {
                    submit(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                partitionService.updateByName(dto);
                            } catch (Exception e) {
                                LogPortal.error("{} >>> refresh 商户[{}] 定时开区失败，分区id [{}] 发生异常:{}", e, traceId, dto.getMerchantId(),
                                        dto.getId(), e.getMessage());
                            }
                            //线程执行完成之后标记信号表示完成
                            countDownLatch.countDown();
                        }
                    });
                }
                //等待线程池任务执行完毕
                countDownLatch.await();
            } else {
                LogPortal.info("{} >>> {} do not get lock ", traceId, lockName);
            }
        } catch (GetLockFailedException e) {
            LogPortal.error("{} >>> [DISTRIBUTED_LOCK_ACQUIRE_FAILED_ZK] 分布式锁获取失败,锁名称为:{}", traceId, lockName);
            LogPortal.error("{} >>> {} 获取lock失败", e, traceId, lockName);
        } catch (Exception e) {
            LogPortal.error("{} >>> {} 定时开区任务执行出错 ", e, traceId, lockName);
            LogPortal.error("{} >>> PARTITION_QUERY_TASK_ERROR: {} 定时开区任务执行出错 ", traceId, lockName);
        } finally {
            if (lock) {
                LogPortal.info(traceId + " >>> " + lockName + " finished.");
                try {
                    distributedLock.releaseLock(lockName);
                } catch (ReleaseLockFailedException e) {
                    LogPortal.error("{} >>> [DISTRIBUTED_LOCK_RELEASE_FAILED_ZK] 分布式锁释放失败,锁名称为:{}", traceId, lockName);
                    LogPortal.error("{} >>> {} 释放失败", e, traceId, lockName);
                }
            }
        }
    }

    public abstract void submit(Runnable task);
}
